home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ms_sh21s.zip / SH210 / SRC / SH10.C < prev    next >
C/C++ Source or Header  |  1992-12-14  |  35KB  |  1,674 lines

  1. /* MS-DOS SHELL - Function Processing
  2.  *
  3.  * MS-DOS SHELL - Copyright (c) 1990,1,2 Data Logic Limited
  4.  *
  5.  * This code is subject to the following copyright restrictions:
  6.  *
  7.  * 1.  Redistribution and use in source and binary forms are permitted
  8.  *     provided that the above copyright notice is duplicated in the
  9.  *     source form and the copyright notice in file sh6.c is displayed
  10.  *     on entry to the program.
  11.  *
  12.  * 2.  The sources (or parts thereof) or objects generated from the sources
  13.  *     (or parts of sources) cannot be sold under any circumstances.
  14.  *
  15.  * Note:  The PrintProcessTree code is based on code written by Kai Uwe Rommel
  16.  *
  17.  *    $Header: /usr/users/istewart/src/shell/sh2.1/RCS/sh10.c,v 2.4 1992/12/14 10:54:56 istewart Exp $
  18.  *
  19.  *    $Log: sh10.c,v $
  20.  *    Revision 2.4  1992/12/14  10:54:56  istewart
  21.  *    BETA 215 Fixes and 2.1 Release
  22.  *
  23.  *    Revision 2.3  1992/11/06  10:03:44  istewart
  24.  *    214 Beta test updates
  25.  *
  26.  *    Revision 2.2  1992/07/16  14:33:34  istewart
  27.  *    Beta 212 Baseline
  28.  *
  29.  *    Revision 2.1  1992/07/10  10:52:48  istewart
  30.  *    211 Beta updates
  31.  *
  32.  *    Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
  33.  *    MS-Shell 2.0 Baseline release
  34.  *
  35.  */
  36.  
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #include <stdio.h>
  40. #include <signal.h>
  41. #include <errno.h>
  42. #include <setjmp.h>
  43. #include <ctype.h>
  44. #include <string.h>
  45. #include <unistd.h>
  46. #include <stdlib.h>
  47. #include <fcntl.h>
  48. #include <limits.h>
  49. #include <dirent.h>
  50. #ifdef OS2
  51. #define INCL_DOSSESMGR
  52. #define INCL_DOSPROCESS
  53. #define INCL_DOSMODULEMGR
  54. #include <os2.h>
  55. #else
  56. #include <dos.h>
  57. #endif
  58. #include "sh.h"
  59.  
  60. /* Function declarations */
  61.  
  62. static void     near    PrintCommand (C_Op *);
  63. static void    near    PrintIOInformation (IO_Actions *);
  64. static void    near    PrintCaseCommand (C_Op *);
  65. static void    near    PrintIndentedString (char *, int);
  66. static void    near    SaveReleaseExecuteTree (C_Op *, void (*)(void *));
  67. static void    near    SaveReleaseCommand (C_Op *, void (*)(void *));
  68. static void    near    SaveReleaseCaseCommand (C_Op *, void (*)(void *));
  69. static C_Op *    near    CopyExecuteTree (C_Op *);
  70. static void    near    CopyCommand (C_Op *, C_Op *);
  71. static C_Op *    near    CopyCaseCommand (C_Op *);
  72. static void        SaveTreeEntry (void *);
  73. static void *    near    DuplicateField (void *, size_t);
  74. static int        FindFunction (void *, void *);
  75. static int        FindAlias (void *, void *);
  76. static int        SearchFunction (void *, void *);
  77. static int        SearchAlias (void *, void *);
  78. static void        UntrackAlias (void *, VISIT, int);
  79. static void        DisplayFunction (void *, VISIT, int);
  80. static void        DisplayAlias (void *, VISIT, int);
  81. #ifdef OS2
  82. static void        DisplayJob (void *, VISIT, int);
  83. static void        CountJob (void *, VISIT, int);
  84. static int        SearchJob (void *, void *);
  85. static int        FindJob (void *, void *);
  86. static void        FindJobByString (void *, VISIT, int);
  87. static int        FindJobByPID (void *, void *);
  88.  
  89. extern USHORT APIENTRY    DosQProcStatus(PVOID pBuf, USHORT cbBuf);
  90. #endif
  91.  
  92. #ifdef OS2
  93. static char    *JobSearchKey;        /* Job search string        */
  94. static int    NumberOfJobs = 0;    /* Number of Jobs        */
  95. static JobList    **JobSearchEntry;    /* Matching entry        */
  96. #endif
  97.  
  98. static bool    DisplayListMode = FALSE;/* Mode for Display Job/Alias    */
  99. static int    Print_indent;        /* Current indent level        */
  100. static char    *LIT_done = "done\n";
  101.  
  102. /*
  103.  * Print ALL functions
  104.  */
  105.  
  106. int PrintAllFunctions (void)
  107. {
  108.     twalk (FunctionTree, DisplayFunction);
  109.     return 0;
  110. }
  111.  
  112. /*
  113.  * TWALK function to display the JOB, FUNCTION and ALIAS trees
  114.  */
  115.  
  116. #ifdef OS2
  117. static void CountJob (void *key, VISIT visit, int level)
  118. {
  119.     if ((visit == postorder) || (visit == leaf))
  120.     NumberOfJobs++;
  121. }
  122.  
  123. static void DisplayJob (void *key, VISIT visit, int level)
  124. {
  125.     if ((visit == postorder) || (visit == leaf))
  126.     {
  127.     printf ("[%d] %c", (*(JobList **)key)->Number,
  128.         ((*(JobList **)key)->Number == CurrentJob)
  129.             ? '+'
  130.             : (((*(JobList **)key)->Number == PreviousJob)
  131.                 ? '-' : ' '));
  132.  
  133.     if (DisplayListMode)
  134.         printf (" %d", (*(JobList **)key)->pid);
  135.  
  136.     putchar (CHAR_TAB);
  137.     fflush (stdout);
  138.     DisplayLineWithControl ((*(JobList **)key)->Command);
  139.     }
  140. }
  141. #endif
  142.  
  143. static void DisplayFunction (void *key, VISIT visit, int level)
  144. {
  145.     if ((visit == postorder) || (visit == leaf))
  146.         PrintFunction ((*(FunctionList **)key)->tree);
  147. }
  148.  
  149. static void DisplayAlias (void *key, VISIT visit, int level)
  150. {
  151.     if (((visit == postorder) || (visit == leaf)) &&
  152.     (!DisplayListMode || (*(AliasList **)key)->Tracked))
  153.     PrintAlias ((*(AliasList **)key)->name);
  154. }
  155.  
  156. /*
  157.  * print the execute tree - used for displaying functions
  158.  */
  159.  
  160. void PrintFunction (register C_Op *t)
  161. {
  162.     char        **wp;
  163.  
  164.     if (t == (C_Op *)NULL)
  165.     return;
  166.  
  167. /* Check for start of print */
  168.  
  169.     if (t->type == TFUNC)
  170.     {
  171.     Print_indent = 0;
  172.     printf (LIT_2Strings, t->str, "()");
  173.     PrintFunction (t->left);
  174.     fflush (stdout);
  175.     return;
  176.     }
  177.  
  178. /* Otherwise, process the tree and print it */
  179.  
  180.     switch (t->type)
  181.     {
  182.     case TPAREN:            /* ()            */
  183.     case TCOM:            /* A command process    */
  184.         PrintCommand (t);
  185.         return;
  186.  
  187.     case TPIPE:            /* Pipe processing        */
  188.         PrintFunction (t->left);
  189.         PrintIndentedString ("|\n", 0);
  190.         PrintFunction (t->right);
  191.         return;
  192.  
  193.     case TLIST:            /* Entries in a for statement    */
  194.         PrintFunction (t->left);
  195.         PrintFunction (t->right);
  196.         return;
  197.  
  198.     case TOR:            /* || and &&            */
  199.     case TAND:
  200.         PrintFunction (t->left);
  201.  
  202.         if (t->right != (C_Op *)NULL)
  203.         {
  204.         PrintIndentedString ((t->type == TAND) ? "&&\n" : "||\n", 0);
  205.         PrintFunction (t->right);
  206.         }
  207.  
  208.         return;
  209.  
  210.     case TFOR:            /* First part of a for statement*/
  211.     case TSELECT:
  212.         PrintIndentedString ((t->type == TFOR) ? "for " : "select ", 0);
  213.         fputs (t->str, stdout);
  214.  
  215.         if ((wp = t->words) != (char **)NULL)
  216.         {
  217.         fputs (" in", stdout);
  218.  
  219.         while (*wp != (char *)NULL)
  220.             printf (" %s", *wp++);
  221.         }
  222.  
  223.         putchar (CHAR_NEW_LINE);
  224.         PrintIndentedString ("do\n", 1);
  225.         PrintFunction (t->left);
  226.         PrintIndentedString (LIT_done, -1);
  227.         return;
  228.  
  229.     case TWHILE:            /* WHILE and UNTIL functions    */
  230.     case TUNTIL:
  231.         PrintIndentedString ((t->type == TWHILE) ? "while " : "until ", 1);
  232.         PrintFunction (t->left);
  233.         PrintIndentedString ("do\n", 0);
  234.         PrintFunction (t->right);
  235.         PrintIndentedString (LIT_done, -1);
  236.         return;
  237.  
  238.     case TIF:            /* IF and ELSE IF functions    */
  239.     case TELIF:
  240.         if (t->type == TIF)
  241.         PrintIndentedString ("if\n", 1);
  242.  
  243.         else
  244.         PrintIndentedString ("elif\n", 1);
  245.  
  246.         PrintFunction (t->left);
  247.  
  248.         if (t->right != (C_Op *)NULL)
  249.         {
  250.         Print_indent -= 1;
  251.         PrintIndentedString ("then\n", 1);
  252.         PrintFunction (t->right->left);
  253.  
  254.         if (t->right->right != (C_Op *)NULL)
  255.         {
  256.             Print_indent -= 1;
  257.  
  258.             if (t->right->right->type != TELIF)
  259.             PrintIndentedString ("else\n", 1);
  260.  
  261.             PrintFunction (t->right->right);
  262.         }
  263.         }
  264.  
  265.         if (t->type == TIF)
  266.         PrintIndentedString ("fi\n", -1);
  267.  
  268.         return;
  269.  
  270.     case TCASE:            /* CASE function        */
  271.         PrintIndentedString ("case ", 1);
  272.         printf (LIT_2Strings, t->str, "in");
  273.         PrintCaseCommand (t->left);
  274.         PrintIndentedString (" esac\n", -1);
  275.         return;
  276.  
  277.     case TBRACE:            /* {} statement            */
  278.         PrintIndentedString ("{\n", 1);
  279.         if (t->left != (C_Op *)NULL)
  280.         PrintFunction (t->left);
  281.  
  282.         PrintIndentedString ("}\n", -1);
  283.         return;
  284.     }
  285. }
  286.  
  287. /*
  288.  * Print a command line
  289.  */
  290.  
  291. static void near PrintCommand (register C_Op *t)
  292. {
  293.     IO_Actions    **iopp;
  294.     char    **owp = t->words;
  295.  
  296. /* Parenthesis ? */
  297.  
  298.     if (t->type == TPAREN)
  299.     {
  300.     PrintIndentedString ("(\n", 1);
  301.     PrintFunction (t->left);
  302.     PrintIndentedString (")", -1);
  303.     }
  304.  
  305.     else
  306.     {
  307.     PrintIndentedString (null, 0);
  308.  
  309.     while (*owp != (char *)NULL)
  310.     {
  311.         fputs (*owp++, stdout);
  312.  
  313.         if (*owp != (char *)NULL)
  314.         putchar (CHAR_SPACE);
  315.     }
  316.     }
  317.  
  318. /* Set up anyother IO required */
  319.  
  320.     if ((iopp = t->ioact) != (IO_Actions **)NULL)
  321.     {
  322.     while (*iopp != (IO_Actions *)NULL)
  323.         PrintIOInformation (*iopp++);
  324.     }
  325.  
  326.     putchar (CHAR_NEW_LINE);
  327. }
  328.  
  329. /*
  330.  * Print the IO re-direction
  331.  */
  332.  
  333. static void near PrintIOInformation (register IO_Actions *iop)
  334. {
  335.     int        unit = iop->io_unit;
  336.     char    *type;
  337.  
  338.     if (unit == IODEFAULT)    /* take default */
  339.     unit = (iop->io_flag & (IOREAD | IOHERE)) ? STDIN_FILENO
  340.                           : STDOUT_FILENO;
  341.  
  342. /* Output unit number */
  343.  
  344.     switch (iop->io_flag)
  345.     {
  346.     case IOHERE:
  347.     case IOHERE | IOXHERE:
  348.         type = "<<";
  349.         break;
  350.  
  351.     case IOREAD:
  352.         type = "<";
  353.         break;
  354.  
  355.     case IOWRITE | IOCAT:
  356.         type = ">>";
  357.         break;
  358.  
  359.     case IOWRITE:
  360.         type = ">";
  361.         break;
  362.  
  363.     case IODUP:
  364.         printf ("%d>&%c", unit, *iop->io_name);
  365.         return;
  366.     }
  367.  
  368.     printf ("%d%s%s", unit, type, iop->io_name);
  369. }
  370.  
  371. /*
  372.  * Print out the contents of a case statement
  373.  */
  374.  
  375. static void near PrintCaseCommand (C_Op *t)
  376. {
  377.     register C_Op    *t1;
  378.     register char    **wp;
  379.  
  380.     if (t == (C_Op *)NULL)
  381.     return;
  382.  
  383. /* type - TLIST - go down the left tree first and then processes this level */
  384.  
  385.     if (t->type == TLIST)
  386.     {
  387.     PrintCaseCommand (t->left);
  388.     t1 = t->right;
  389.     }
  390.  
  391.     else
  392.     t1 = t;
  393.  
  394. /* Output the conditions */
  395.  
  396.     PrintIndentedString (null, 0);
  397.  
  398.     for (wp = t1->words; *wp != (char *)NULL;)
  399.     {
  400.     printf ("%s%s", *wp, *(wp + 1) != (char *)NULL ? " | " : null);
  401.     ++wp;
  402.     }
  403.  
  404.     puts (" )");
  405.     Print_indent += 1;
  406.  
  407. /* Output the commands */
  408.  
  409.     PrintFunction (t1->left);
  410.     PrintIndentedString (";;\n", -1);
  411. }
  412.  
  413. /*
  414.  * Print an indented string
  415.  */
  416.  
  417. static void near PrintIndentedString (char *cp, int indent)
  418. {
  419.     int        i;
  420.  
  421.     if (indent < 0)
  422.     Print_indent += indent;
  423.  
  424.     for (i = 0; i < (Print_indent / 2); i++)
  425.     putchar ('\t');
  426.  
  427.     if (Print_indent % 2)
  428.     fputs ("    ", stdout);
  429.  
  430.     fputs (cp, stdout);
  431.  
  432.     if (indent > 0)
  433.     Print_indent += indent;
  434. }
  435.  
  436. /*
  437.  * TWALK and TDELETE compare functions for FUNCTION, ALIAS and JOB trees
  438.  *
  439.  * Note: We know about these two function, so we know the key is always
  440.  *       the first parameter.  So we only pass the char * not the FunctionList
  441.  *       pointer (in the case of JOB, its an int *)
  442.  */
  443.  
  444. static int FindFunction (void *key1, void *key2)
  445. {
  446.     return strcmp (key1, ((FunctionList *)key2)->tree->str);
  447. }
  448.  
  449. static int FindAlias (void *key1, void *key2)
  450. {
  451.     return strcmp (key1, ((AliasList *)key2)->name);
  452. }
  453.  
  454. #ifdef OS2
  455. /* By string name */
  456.  
  457. static void FindJobByString (void *key, VISIT visit, int level)
  458. {
  459.     if (JobSearchEntry != (JobList **)NULL)
  460.     return;
  461.  
  462.     if (((visit == postorder) || (visit == leaf)) &&
  463.     ((*JobSearchKey == '?') && 
  464.      (strstr (((JobList *)key)->Command, JobSearchKey) != (char *)NULL)) ||
  465.     ((*JobSearchKey != '?') && 
  466.      (strncmp (JobSearchKey, ((JobList *)key)->Command,
  467.            strlen (JobSearchKey)) == 0)))
  468.     JobSearchEntry = &key;
  469. }
  470.  
  471. /* By process id */
  472.  
  473. static int FindJobByPID (void *key1, void *key2)
  474. {
  475.     return *(PID *)key1 - ((JobList *)key2)->pid;
  476. }
  477.  
  478. /* By job number */
  479.  
  480. static int FindJob (void *key1, void *key2)
  481. {
  482.     return *(int *)key1 - ((JobList *)key2)->Number;
  483. }
  484. #endif
  485.  
  486. /*
  487.  * Look up a function in the save tree
  488.  */
  489.  
  490. FunctionList *LookUpFunction (char *name)
  491. {
  492.     FunctionList    **fp = (FunctionList **)tfind (name, &FunctionTree,
  493.                                FindFunction);
  494.  
  495.     return fp != (FunctionList **)NULL ? *fp : (FunctionList *)NULL;
  496. }
  497.  
  498. /*
  499.  * Delete a function tree
  500.  */
  501.  
  502. void DeleteFunction (C_Op *t)
  503. {
  504.     char            *name = t->str;
  505.     register FunctionList    *fp = LookUpFunction (name);
  506.     void            (*save_signal)(int);
  507.  
  508.     if (fp == (FunctionList *)NULL)
  509.     return;
  510.  
  511. /* Disable signals */
  512.  
  513.     save_signal = signal (SIGINT, SIG_IGN);
  514.  
  515. /* Free the tree and delete the entry */
  516.  
  517.     tdelete (name, &FunctionTree, FindFunction);
  518.     SaveReleaseExecuteTree (fp->tree, ReleaseMemoryCell);
  519.     ReleaseMemoryCell ((void *)fp);
  520.  
  521. /* Restore signals */
  522.  
  523.     signal (SIGINT, save_signal);
  524. }
  525.  
  526. /*
  527.  * TSEARCH compare functions for FUNCTION, ALIAS and JOB trees
  528.  */
  529.  
  530. static int SearchFunction (void *key1, void *key2)
  531. {
  532.     return strcmp (((FunctionList *)key1)->tree->str,
  533.            ((FunctionList *)key2)->tree->str);
  534. }
  535.  
  536. static int SearchAlias (void *key1, void *key2)
  537. {
  538.     return strcmp (((AliasList *)key1)->name, ((AliasList *)key2)->name);
  539. }
  540.  
  541. #ifdef OS2
  542. static int SearchJob (void *key1, void *key2)
  543. {
  544.     return ((JobList *)key1)->Number - ((JobList *)key2)->Number;
  545. }
  546. #endif
  547.  
  548. /*
  549.  * Save a function tree
  550.  */
  551.  
  552. bool SaveFunction (C_Op *t)
  553. {
  554.     char            *name = t->str;
  555.     register FunctionList    *fp;
  556.     void            (*save_signal)(int);
  557.  
  558.     if (!IsValidAliasName (name, FALSE))
  559.     {
  560.     PrintWarningMessage (BasicErrorMessage, name, "Invalid function name");
  561.     return FALSE;
  562.     }
  563.  
  564. /* Create new entry */
  565.  
  566.     if ((fp = (FunctionList *)GetAllocatedSpace (sizeof (FunctionList)))
  567.     == (FunctionList *)NULL)
  568.     return FALSE;
  569.  
  570. /* Delete the old function if it exists */
  571.  
  572.     DeleteFunction (t);
  573.  
  574. /* Disable signals */
  575.  
  576.     save_signal = signal (SIGINT, SIG_IGN);
  577.     fp->tree = t;
  578.     fp->Traced = FALSE;
  579.  
  580. /* Set up the tree */
  581.  
  582.     if (tsearch (fp, &FunctionTree, SearchFunction) != (void *)NULL)
  583.     {
  584.     SetMemoryAreaNumber ((void *)fp, 0);
  585.     SaveReleaseExecuteTree (t, SaveTreeEntry);
  586.     }
  587.  
  588. /* Restore signals */
  589.  
  590.     signal (SIGINT, save_signal);
  591.     return TRUE;
  592. }
  593.  
  594. /*
  595.  * Set ExTree areas to zero function
  596.  */
  597.  
  598. static void  SaveTreeEntry (void *s)
  599. {
  600.     SetMemoryAreaNumber (s, 0);
  601. }
  602.  
  603. /*
  604.  * Set/Free function tree area by recursively processing of tree
  605.  */
  606.  
  607. static void near SaveReleaseExecuteTree (C_Op *t, void (* func)(void *))
  608. {
  609.     char        **wp;
  610.  
  611.     if (t == (C_Op *)NULL)
  612.     return;
  613.  
  614. /* Check for start of print */
  615.  
  616.     if (t->type == TFUNC)
  617.     {
  618.     (*func)((void *)t->str);
  619.     SaveReleaseExecuteTree (t->left, func);
  620.     }
  621.  
  622. /* Otherwise, process the tree and print it */
  623.  
  624.     switch (t->type)
  625.     {
  626.     case TPAREN:            /* ()            */
  627.     case TCOM:            /* A command process    */
  628.         SaveReleaseCommand (t, func);
  629.         break;
  630.  
  631.     case TPIPE:            /* Pipe processing        */
  632.     case TLIST:            /* Entries in a for statement    */
  633.     case TOR:            /* || and &&            */
  634.     case TAND:
  635.     case TWHILE:            /* WHILE and UNTIL functions    */
  636.     case TUNTIL:
  637.         SaveReleaseExecuteTree (t->left, func);
  638.         SaveReleaseExecuteTree (t->right, func);
  639.         break;
  640.  
  641.     case TFOR:            /* First part of a for statement*/
  642.     case TSELECT:
  643.         (*func)((void *)t->str);
  644.  
  645.         if ((wp = t->words) != (char **)NULL)
  646.         {
  647.         while (*wp != (char *)NULL)
  648.             (*func) ((void *)*wp++);
  649.  
  650.         (*func)((void *)t->words);
  651.         }
  652.  
  653.         SaveReleaseExecuteTree (t->left, func);
  654.         break;
  655.  
  656.     case TIF:            /* IF and ELSE IF functions    */
  657.     case TELIF:
  658.         if (t->right != (C_Op *)NULL)
  659.         {
  660.         SaveReleaseExecuteTree (t->right->left, func);
  661.         SaveReleaseExecuteTree (t->right->right, func);
  662.         (*func)((void *)t->right);
  663.         }
  664.  
  665.     case TBRACE:            /* {} statement            */
  666.         SaveReleaseExecuteTree (t->left, func);
  667.         break;
  668.  
  669.     case TCASE:            /* CASE function        */
  670.         (*func)((void *)t->str);
  671.         SaveReleaseCaseCommand (t->left, func);
  672.         break;
  673.     }
  674.  
  675.     (*func)((void *)t);
  676. }
  677.  
  678. /*
  679.  * Set/Free a command line
  680.  */
  681.  
  682. static void near SaveReleaseCommand (C_Op *t, void (* func)(void *))
  683. {
  684.     IO_Actions    **iopp;
  685.     char    **wp = t->words;
  686.  
  687. /* Parenthesis ? */
  688.  
  689.     if (t->type == TPAREN)
  690.     SaveReleaseExecuteTree (t->left, func);
  691.  
  692.     else
  693.     {
  694.     while (*wp != (char *)NULL)
  695.         (*func)((void *)*wp++);
  696.  
  697.     (*func) ((void *)t->words);
  698.     }
  699.  
  700. /* Process up any IO required */
  701.  
  702.     if ((iopp = t->ioact) != (IO_Actions **)NULL)
  703.     {
  704.     while (*iopp != (IO_Actions *)NULL)
  705.     {
  706.         (*func)((void *)(*iopp)->io_name);
  707.         (*func)((void *)*iopp);
  708.         iopp++;
  709.     }
  710.  
  711.     (*func)((void *)t->ioact);
  712.     }
  713. }
  714.  
  715. /*
  716.  * Set/Free the contents of a case statement
  717.  */
  718.  
  719. static void near SaveReleaseCaseCommand (C_Op *t, void (* func)(void *))
  720. {
  721.     register C_Op    *t1;
  722.     register char    **wp;
  723.  
  724.     if (t == (C_Op *)NULL)
  725.     return;
  726.  
  727. /* type - TLIST - go down the left tree first and then processes this level */
  728.  
  729.     if (t->type == TLIST)
  730.     {
  731.     SaveReleaseCaseCommand (t->left, func);
  732.     (*func)((void *)t->left);
  733.     t1 = t->right;
  734.     }
  735.  
  736.     else
  737.     t1 = t;
  738.  
  739. /* Set/Free the conditions */
  740.  
  741.     for (wp = t1->words; *wp != (char *)NULL;)
  742.     (*func)((void *)*(wp++));
  743.  
  744.     (*func)((void *)t1->words);
  745.  
  746.     SaveReleaseExecuteTree (t1->left, func);
  747.  
  748.     if (t1 == t->right)
  749.     (*func)((void *)t->right);
  750.  
  751.     (*func)((void *)t);
  752. }
  753.  
  754. /*
  755.  * Copy function tree area by recursively processing of tree
  756.  */
  757.  
  758. static C_Op * near CopyExecuteTree (C_Op *Old_t)
  759. {
  760.     char    **wp;
  761.     C_Op    *New_t;
  762.     Word_B    *wb = (Word_B *)NULL;
  763.  
  764.     if (Old_t == (C_Op *)NULL)
  765.     return (C_Op *)NULL;
  766.  
  767.     New_t = (C_Op *) DuplicateField (Old_t, sizeof (C_Op));
  768.  
  769. /* Check for start of print */
  770.  
  771.     if (Old_t->type == TFUNC)
  772.     {
  773.     New_t->str = StringCopy (Old_t->str);
  774.     New_t->left = CopyExecuteTree (Old_t->left);
  775.     }
  776.  
  777. /* Otherwise, process the tree and print it */
  778.  
  779.     switch (Old_t->type)
  780.     {
  781.     case TPAREN:            /* ()            */
  782.     case TCOM:            /* A command process    */
  783.         CopyCommand (Old_t, New_t);
  784.         break;
  785.  
  786.     case TPIPE:            /* Pipe processing        */
  787.     case TLIST:            /* Entries in a for statement    */
  788.     case TOR:            /* || and &&            */
  789.     case TAND:
  790.     case TWHILE:            /* WHILE and UNTIL functions    */
  791.     case TUNTIL:
  792.         New_t->left  = CopyExecuteTree (Old_t->left);
  793.         New_t->right = CopyExecuteTree (Old_t->right);
  794.         break;
  795.  
  796.     case TFOR:            /* First part of a for statement*/
  797.     case TSELECT:
  798.         New_t->str = StringCopy (Old_t->str);
  799.  
  800.         if ((wp = Old_t->words) != (char **)NULL)
  801.         {
  802.         while (*wp != (char *)NULL)
  803.             wb = AddWordToBlock (StringCopy (*(wp++)), wb);
  804.  
  805.         New_t->words = GetWordList (AddWordToBlock (NOWORD, wb));
  806.         }
  807.  
  808.         New_t->left = CopyExecuteTree (Old_t->left);
  809.         break;
  810.  
  811.     case TIF:            /* IF and ELSE IF functions    */
  812.     case TELIF:
  813.         if (Old_t->right != (C_Op *)NULL)
  814.         {
  815.         New_t->right = (C_Op *)DuplicateField (Old_t->right,
  816.                                sizeof (C_Op));
  817.         New_t->right->left  = CopyExecuteTree (Old_t->right->left);
  818.         New_t->right->right = CopyExecuteTree (Old_t->right->right);
  819.         }
  820.  
  821.     case TBRACE:            /* {} statement            */
  822.         New_t->left = CopyExecuteTree (Old_t->left);
  823.         break;
  824.  
  825.     case TCASE:            /* CASE function        */
  826.         New_t->str = StringCopy (Old_t->str);
  827.         New_t->left = CopyCaseCommand (Old_t->left);
  828.         break;
  829.     }
  830.  
  831.     return New_t;
  832. }
  833.  
  834. /*
  835.  * Copy a command line
  836.  */
  837.  
  838. static void near CopyCommand (C_Op *Old_t, C_Op *New_t)
  839. {
  840.     IO_Actions    **iopp;
  841.     char    **wp = Old_t->words;
  842.     Word_B    *wb = (Word_B *)NULL;
  843.     IO_Actions    *iop;
  844.  
  845. /* Parenthesis ? */
  846.  
  847.     if (Old_t->type == TPAREN)
  848.     New_t->left = CopyExecuteTree (Old_t->left);
  849.  
  850.     else
  851.     {
  852.     while (*wp != (char *)NULL)
  853.         wb = AddWordToBlock (StringCopy (*(wp++)), wb);
  854.  
  855.     New_t->words = GetWordList (AddWordToBlock (NOWORD, wb));
  856.     }
  857.  
  858. /* Process up any IO required */
  859.  
  860.     if ((iopp = Old_t->ioact) != (IO_Actions **)NULL)
  861.     {
  862.     wb = (Word_B *)NULL;
  863.  
  864.     while (*iopp != (IO_Actions *)NULL)
  865.     {
  866.         iop = (IO_Actions *)DuplicateField (*iopp, sizeof (IO_Actions));
  867.         iop->io_name = StringCopy ((*iopp)->io_name);
  868.         wb = AddWordToBlock ((char *)iop, wb);
  869.         ++iopp;
  870.     }
  871.  
  872.      New_t->ioact = (IO_Actions **)GetWordList (AddWordToBlock (NOWORD, wb));
  873.     }
  874. }
  875.  
  876. /*
  877.  * Copy the contents of a case statement
  878.  */
  879.  
  880. static C_Op * near CopyCaseCommand (C_Op *Old_t)
  881. {
  882.     register C_Op    *Old_t1, *New_t, *New_t1;
  883.     register char    **wp;
  884.     Word_B        *wb = (Word_B *)NULL;
  885.  
  886.     if (Old_t == (C_Op *)NULL)
  887.     return (C_Op *)NULL;
  888.  
  889. /* type - TLIST - go down the left tree first and then processes this level */
  890.  
  891.     New_t = (C_Op *)DuplicateField (Old_t, sizeof (C_Op));
  892.  
  893.     if (Old_t->type == TLIST)
  894.     {
  895.     New_t->left  = CopyCaseCommand (Old_t->left);
  896.     New_t->right = (C_Op *)DuplicateField (Old_t->right, sizeof (C_Op));
  897.     Old_t1         = Old_t->right;
  898.     New_t1         = New_t->right;
  899.     }
  900.  
  901.     else
  902.     {
  903.     New_t1 = New_t;
  904.     Old_t1 = Old_t;
  905.     }
  906.  
  907. /* Duplicate the word block */
  908.  
  909.     wp = Old_t1->words;
  910.  
  911.     while (*wp != (char *)NULL)
  912.     wb = AddWordToBlock (StringCopy (*(wp++)), wb);
  913.  
  914.     New_t1->words = GetWordList (AddWordToBlock (NOWORD, wb));
  915.     New_t1->left  = CopyExecuteTree (Old_t1->left);
  916.     return New_t;
  917. }
  918.  
  919.  
  920. /*
  921.  * Duplicate a field
  922.  */
  923.  
  924. static void * near DuplicateField (void *source, size_t size)
  925. {
  926.     return memcpy (GetAllocatedSpace (size), source, size);
  927. }
  928.  
  929. /* Duplicate the tree */
  930.  
  931. C_Op        *CopyFunction (C_Op *Old_t)
  932. {
  933.     int        *save_ErrorReturnPoint;
  934.     jmp_buf    new_ErrorReturnPoint;
  935.     C_Op    *New_t = (C_Op *)NULL;
  936.  
  937. /* Set up for error handling - like out of space */
  938.  
  939.     save_ErrorReturnPoint = e.ErrorReturnPoint;
  940.  
  941.     if (setjmp (new_ErrorReturnPoint) == 0)
  942.     New_t = CopyExecuteTree (Old_t);
  943.  
  944.     e.ErrorReturnPoint = save_ErrorReturnPoint;
  945.     return New_t;
  946. }
  947.  
  948. /*
  949.  * Alias processing
  950.  */
  951.  
  952. void PrintAlias (char *name)
  953. {
  954.     register AliasList    *al = LookUpAlias (name, FALSE);
  955.  
  956.     if ((al == (AliasList *)NULL) || (al->value == null))
  957.     return;
  958.  
  959.     printf (ListVarFormat, name, al->value);
  960. }
  961.  
  962. /*
  963.  * Print All Aliases
  964.  */
  965.  
  966. int  PrintAllAlias (bool tracked)
  967. {
  968.     DisplayListMode = tracked;        /* Set mode            */
  969.  
  970.     twalk (AliasTree, DisplayAlias);
  971.     return 0;
  972. }
  973.  
  974. /*
  975.  * Save an alias
  976.  */
  977.  
  978. bool SaveAlias (char *name, char *arguments, bool tracked)
  979. {
  980.     register AliasList    *al;
  981.     void        (*save_signal)(int);
  982.  
  983.  
  984. /* Create new entry */
  985.  
  986.     if (((al = (AliasList *)GetAllocatedSpace (sizeof (AliasList)))
  987.         == (AliasList *)NULL) ||
  988.     ((al->name = GetAllocatedSpace (strlen (name) + 1)) == (char *)NULL))
  989.     return FALSE;
  990.  
  991.     if ((arguments != null) &&
  992.     ((al->value = GetAllocatedSpace (strlen (arguments) + 1))
  993.         == (char *)NULL))
  994.     return FALSE;
  995.  
  996. /* Delete old name */
  997.  
  998.     DeleteAlias (name);
  999.  
  1000. /* Disable signals */
  1001.  
  1002.     save_signal = signal (SIGINT, SIG_IGN);
  1003.     strcpy (al->name, name);
  1004.  
  1005. /* Add it to the tree */
  1006.  
  1007.     if (tsearch (al, &AliasTree, SearchAlias) != (void *)NULL)
  1008.     {
  1009.     SetMemoryAreaNumber ((void *)al, 0);
  1010.     SetMemoryAreaNumber ((void *)al->name, 0);
  1011.  
  1012.     if (arguments != null)
  1013.         SetMemoryAreaNumber ((void *)strcpy (al->value, arguments), 0);
  1014.  
  1015.     else
  1016.         al->value = null;
  1017.  
  1018.         al->Tracked = tracked;
  1019.     }
  1020.  
  1021.  
  1022. /* Restore signals */
  1023.  
  1024.     signal (SIGINT, save_signal);
  1025.     return TRUE;
  1026. }
  1027.  
  1028. /*
  1029.  * Delete an alias
  1030.  */
  1031.  
  1032. void DeleteAlias (char *name)
  1033. {
  1034.     register AliasList    **alp = (AliasList **)tfind (name, &AliasTree,
  1035.                              FindAlias);
  1036.     void        (*save_signal)(int);
  1037.     register AliasList    *al;
  1038.  
  1039.     if (alp == (AliasList **)NULL)
  1040.     return;
  1041.  
  1042. /* Disable signals */
  1043.  
  1044.     save_signal = signal (SIGINT, SIG_IGN);
  1045.  
  1046. /* Delete the tree entry and release the memory */
  1047.  
  1048.     al = *alp;
  1049.     tdelete (name, &AliasTree, FindAlias);
  1050.     ReleaseMemoryCell ((void *)al->name);
  1051.  
  1052.     if (al->value != null)
  1053.     ReleaseMemoryCell ((void *)al->value);
  1054.  
  1055.     ReleaseMemoryCell ((void *)al);
  1056.  
  1057. /* Restore signals */
  1058.  
  1059.     signal (SIGINT, save_signal);
  1060. }
  1061.  
  1062. /*
  1063.  * Search for an Alias
  1064.  */
  1065.  
  1066. AliasList    *LookUpAlias (char *name, bool CreateTracked)
  1067. {
  1068.     AliasList    **alp = (AliasList **)tfind (name, &AliasTree, FindAlias);
  1069.     char    *path;
  1070.  
  1071. /* If we found a tracked alias, which has been untracked, re-track it if
  1072.  * necesary
  1073.  */
  1074.  
  1075.     if ((alp != (AliasList **)NULL) && ((*alp)->value == null))
  1076.     {
  1077.         if (CreateTracked &&
  1078.         ((path = AllocateMemoryCell (FFNAME_MAX + 4)) != (char *)NULL) &&
  1079.         (FindLocationOfExecutable (path, name) == EXTENSION_NOT_FOUND))
  1080.         {
  1081.         SetMemoryAreaNumber ((void *)path, 0);
  1082.         (*alp)->value = path;
  1083.         return *alp;
  1084.         }
  1085.  
  1086.         else
  1087.             return (AliasList *)NULL;
  1088.     }
  1089.  
  1090.     return (alp == (AliasList **)NULL) ? (AliasList *)NULL : *alp;
  1091. }
  1092.  
  1093. /*
  1094.  * Check for valid alias name
  1095.  */
  1096.  
  1097. bool IsValidAliasName (char *s, bool alias)
  1098. {
  1099.     if (!isalpha (*s) || LookUpSymbol (s))
  1100.     return FALSE;
  1101.  
  1102.     while (isalnum (*s))
  1103.         ++s;
  1104.  
  1105.     return (*s) ? FALSE : TRUE;
  1106. }
  1107.  
  1108. /*
  1109.  * Untrack all Aliases
  1110.  */
  1111.  
  1112. void UnTrackAllAliases (void)
  1113. {
  1114.     twalk (AliasTree, UntrackAlias);
  1115. }
  1116.  
  1117. /*
  1118.  * The associate TWALK function
  1119.  */
  1120.  
  1121. static void  UntrackAlias (void *key, VISIT visit, int level)
  1122. {
  1123.     AliasList    *al = *(AliasList **)key;
  1124.  
  1125.     if (((visit == postorder) || (visit == leaf)) && al->Tracked &&
  1126.         (al->value != null))
  1127.     {
  1128.      ReleaseMemoryCell ((void *)al->value);
  1129.      al->value = null;
  1130.     }
  1131. }
  1132.  
  1133. #ifdef OS2
  1134. /*
  1135.  * Look up a job in the save tree
  1136.  */
  1137.  
  1138. JobList *LookUpJob (int JobNumber)
  1139. {
  1140.     JobList    **jp = (JobList **)tfind (&JobNumber, &JobTree, FindJob);
  1141.  
  1142.     return jp != (JobList **)NULL ? *jp : (JobList *)NULL;
  1143. }
  1144.  
  1145. /*
  1146.  * Search for a job
  1147.  */
  1148.  
  1149. JobList    *SearchForJob (char *String)
  1150. {
  1151.     JobSearchKey = String;
  1152.     JobSearchEntry = (JobList **)NULL;
  1153.  
  1154.     if ((strcmp (String, "%") == 0) || (strcmp (String, "+") == 0))
  1155.     return LookUpJob (CurrentJob);
  1156.  
  1157.     else if (strcmp (String, "-") == 0)
  1158.     return LookUpJob (PreviousJob);
  1159.  
  1160. /* Search for it */
  1161.  
  1162.     twalk (JobTree, FindJobByString);
  1163.     return JobSearchEntry != (JobList **)NULL ? *JobSearchEntry
  1164.                           : (JobList *)NULL;
  1165. }
  1166.  
  1167. /*
  1168.  * Delete a job tree
  1169.  */
  1170.  
  1171. void DeleteJob (PID pid)
  1172. {
  1173.     register JobList    **jpp = (JobList **)tfind (&pid, &JobTree,
  1174.                            FindJobByPID);
  1175.     void        (*save_signal)(int);
  1176.     JobList        *jp;
  1177.  
  1178.     if (jpp == (JobList **)NULL)
  1179.     return;
  1180.  
  1181. /* Disable signals */
  1182.  
  1183.     save_signal = signal (SIGINT, SIG_IGN);
  1184.     jp = *jpp;
  1185.  
  1186. /* Free the tree and delete the entry */
  1187.  
  1188.     tdelete (&pid, &JobTree, FindJobByPID);
  1189.  
  1190.     if (jp->Number == PreviousJob)
  1191.     PreviousJob = 0;
  1192.  
  1193.     if (jp->Number == CurrentJob)
  1194.     CurrentJob = PreviousJob;
  1195.  
  1196.     ReleaseMemoryCell ((void *)jp->Command);
  1197.     ReleaseMemoryCell ((void *)jp);
  1198.  
  1199. /* Restore signals */
  1200.  
  1201.     signal (SIGINT, save_signal);
  1202. }
  1203.  
  1204. /*
  1205.  * Save a job ID
  1206.  */
  1207.  
  1208. int AddNewJob (PID pid, char *command)
  1209. {
  1210.     register JobList    *jp;
  1211.     static int        JobNumber = 1;
  1212.     void        (*save_signal)(int);
  1213.     char        *tmp;
  1214.  
  1215. /* We if we can get the full command */
  1216.  
  1217.    if ((tmp = GetLastHistoryString ()) != (char *)NULL)
  1218.        command = tmp;
  1219.  
  1220. /* Create new entry */
  1221.  
  1222.     if (((jp = (JobList *)GetAllocatedSpace (sizeof (JobList))) == (JobList *)NULL) ||
  1223.     ((jp->Command = GetAllocatedSpace (strlen (command) + 1)) == (char *)NULL))
  1224.     return 0;
  1225.  
  1226. /* Get the next available job number */
  1227.  
  1228.     while (TRUE)
  1229.     {
  1230.     jp->pid = pid;
  1231.     jp->Number = JobNumber++;
  1232.  
  1233.     if (JobNumber > 32000)
  1234.         JobNumber = 1;
  1235.  
  1236.     if (tfind (jp, &JobTree, SearchJob) == (void *)NULL)
  1237.         break;
  1238.     }
  1239.  
  1240. /* Disable signals */
  1241.  
  1242.     save_signal = signal (SIGINT, SIG_IGN);
  1243.  
  1244.     if (tsearch (jp, &JobTree, SearchJob) != (void *)NULL)
  1245.     {
  1246.     SetMemoryAreaNumber ((void *)jp, 0);
  1247.     SetMemoryAreaNumber ((void *)strcpy (jp->Command, command), 0);
  1248.     PATH_TO_UNIX (jp->Command);
  1249.     }
  1250.  
  1251. /* Restore signals */
  1252.  
  1253.     signal (SIGINT, save_signal);
  1254.  
  1255.     PreviousJob = CurrentJob;
  1256.     return CurrentJob = jp->Number;
  1257. }
  1258.  
  1259. /*
  1260.  * Display Jobs
  1261.  */
  1262.  
  1263. int PrintJobs (bool Mode)
  1264. {
  1265.     DisplayListMode = Mode;        /* Set mode            */
  1266.  
  1267.     twalk (JobTree, DisplayJob);
  1268.     return 0;
  1269. }
  1270.  
  1271. /*
  1272.  * Count the number of active jobs
  1273.  */
  1274.  
  1275. int NumberOfActiveJobs (void)
  1276. {
  1277.     NumberOfJobs = 0;
  1278.  
  1279.     twalk (JobTree, CountJob);
  1280.     return NumberOfJobs;
  1281. }
  1282.  
  1283. /*
  1284.  * Print Process Tree
  1285.  *
  1286.  * Declare OS2 1.x 16-bit version structures
  1287.  */
  1288.  
  1289. typedef struct process
  1290. {
  1291.     USHORT    pid;
  1292.     USHORT    ppid;
  1293.     USHORT    threads;
  1294.     USHORT    children;
  1295.     USHORT    modhandle;
  1296.     USHORT    module;
  1297. } V1Process_t;
  1298.  
  1299. typedef struct module
  1300. {
  1301.     USHORT    modhandle;
  1302.     USHORT    max_dependents;
  1303.     USHORT    *dependents;
  1304.     UCHAR    *modname;
  1305. } V1Module_t;
  1306.  
  1307. struct ProcessInfo
  1308. {
  1309.     V1Process_t        **V1Processes;
  1310.     V1Module_t        **V1Modules;
  1311.     USHORT        M_Processes;
  1312.     USHORT        N_Processes;
  1313.     USHORT        M_Modules;
  1314.     USHORT        N_Modules;
  1315. };
  1316.  
  1317. /*
  1318.  * OS2 2.0 - 32 Bit version structures
  1319.  */
  1320.  
  1321. #define PTR(ptr, ofs)  ((void *)((char *)(((ULONG) ps & 0xFFFF0000) | (USHORT) (ptr)) + (ofs)))
  1322.  
  1323. /* Process Status structures */
  1324.  
  1325. struct V2_ProcessStatus
  1326. {
  1327.     ULONG    summary;
  1328.     ULONG    processes;
  1329.     ULONG    semaphores;
  1330.     ULONG    unknown1;
  1331.     ULONG    sharedmemory;
  1332.     ULONG    modules;
  1333.     ULONG    unknown2;
  1334.     ULONG    unknown3;
  1335. };
  1336.  
  1337. typedef struct process2
  1338. {
  1339.     ULONG    type;
  1340.     ULONG    threadlist;
  1341.     USHORT    processid;
  1342.     USHORT    parentid;
  1343.     ULONG    unknown1;
  1344.     ULONG    unknown2;
  1345.     USHORT    sessionid;
  1346.     USHORT    unknown3;
  1347.     USHORT    modulehandle;
  1348.     USHORT    threads;
  1349.     USHORT    sessiontype;
  1350.   /* lots of other unknown data */
  1351. } V2Process_t;
  1352.  
  1353. typedef struct thread2
  1354. {
  1355.     ULONG    unknown1;
  1356.     USHORT    threadid;
  1357.     USHORT    threadsysid;
  1358.     ULONG    blockid;
  1359.     USHORT    priority;
  1360.     USHORT    unknown2;
  1361.     ULONG    unknown3;
  1362.     ULONG    unknown4;
  1363.     USHORT    status;
  1364.     USHORT    unknown5;
  1365. } V2Thread_t;
  1366.  
  1367. /*
  1368.  * OS2 1.x - Parse the kernel process information
  1369.  */
  1370.  
  1371. static bool near Parse_V1ProcessTable (UCHAR * bBuf, struct ProcessInfo *pi)
  1372. {
  1373.     USHORT    sel, offs;
  1374.     USHORT    type, tpid;
  1375.     USHORT    count, kount;
  1376.     UCHAR    buffer[256];
  1377.     UCHAR    *cptr, *ptr;
  1378.  
  1379.     ptr = bBuf;
  1380.     sel = SELECTOROF(ptr);
  1381.  
  1382.     while ((type = *(USHORT *) ptr) != 0xFFFFU )
  1383.     {
  1384.     ptr += 2;
  1385.     offs = *(USHORT *) ptr;
  1386.     ptr += 2;
  1387.  
  1388.     switch ( type )
  1389.     {
  1390.         case 0:                    /* Process */
  1391.         if (pi->N_Processes >= pi->M_Processes)
  1392.         {
  1393.             V1Process_t    **newp;
  1394.  
  1395.             newp = (V1Process_t **)GetAllocatedSpace (
  1396.                    (pi->M_Processes + 50) * sizeof (V1Process_t *));
  1397.  
  1398.             if (newp == (V1Process_t **)NULL)
  1399.             return TRUE;
  1400.  
  1401.             memcpy ((void *)newp, (void *)pi->V1Processes,
  1402.                 sizeof (V1Process_t *) * pi->M_Processes);
  1403.             ReleaseMemoryCell ((void *)pi->V1Processes);
  1404.  
  1405.             pi->V1Processes = newp;
  1406.             pi->M_Processes += 50;
  1407.         }
  1408.  
  1409. /* Create the process entry */
  1410.  
  1411.         pi->V1Processes[pi->N_Processes] =
  1412.             (V1Process_t *) GetAllocatedSpace (sizeof (V1Process_t));
  1413.  
  1414.         if (pi->V1Processes[pi->N_Processes] == (V1Process_t *)NULL)
  1415.             return TRUE;
  1416.  
  1417.         pi->V1Processes[pi->N_Processes]->pid = *(USHORT *)ptr;
  1418.         ptr += 2;
  1419.         pi->V1Processes[pi->N_Processes]->ppid = *(USHORT *) ptr;
  1420.         ptr += 2;
  1421.         ptr += 2;
  1422.         pi->V1Processes[pi->N_Processes]->modhandle = *(USHORT *) ptr;
  1423.         pi->V1Processes[pi->N_Processes++]->threads = 0;
  1424.  
  1425.         break;
  1426.  
  1427.         case 1:                 /* Thread     */
  1428.         ptr += 2;
  1429.         tpid = *(USHORT *) ptr;
  1430.  
  1431. /* Increment the thread count for the process */
  1432.  
  1433.         for (count = 0; count < pi->N_Processes; count++)
  1434.         {
  1435.             if (pi->V1Processes[count]->pid == tpid)
  1436.             {
  1437.             ++pi->V1Processes[count]->threads;
  1438.             break;
  1439.             }
  1440.         }
  1441.  
  1442.         break;
  1443.  
  1444.         case 2:                    /* module    */
  1445.         if (pi->N_Modules >= pi->M_Modules)
  1446.         {
  1447.             V1Module_t    **newm;
  1448.  
  1449.             newm = (V1Module_t **)GetAllocatedSpace (
  1450.                 (pi->M_Modules + 50) * sizeof (V1Module_t *));
  1451.  
  1452.             if (newm == (V1Module_t **)NULL)
  1453.             return TRUE;
  1454.  
  1455.             memcpy ((void *)newm, (void *)pi->V1Modules,
  1456.                 sizeof (V1Module_t *) * pi->M_Modules);
  1457.             ReleaseMemoryCell ((void *)pi->V1Modules);
  1458.  
  1459.             pi->V1Modules = newm;
  1460.             pi->M_Modules += 50;
  1461.         }
  1462.  
  1463.         pi->V1Modules[pi->N_Modules]
  1464.             = (V1Module_t *)GetAllocatedSpace (sizeof(V1Module_t));
  1465.  
  1466.         if (pi->V1Modules[pi->N_Modules] == (V1Module_t *)NULL)
  1467.             return TRUE;
  1468.  
  1469.         pi->V1Modules[pi->N_Modules]->modhandle = *(USHORT *) ptr;
  1470.         ptr += 2;
  1471.         pi->V1Modules[pi->N_Modules]->max_dependents = *(USHORT *) ptr;
  1472.         ptr += 2;
  1473.         ptr += 2;
  1474.         ptr += 2;
  1475.  
  1476.         if (pi->V1Modules[pi->N_Modules] -> max_dependents)
  1477.             ptr += (pi->V1Modules[pi->N_Modules] -> max_dependents) * 2;
  1478.  
  1479.         for (cptr = buffer; *cptr++ = *ptr++;)
  1480.             continue;
  1481.  
  1482.         if ((pi->V1Modules[pi->N_Modules]->modname =
  1483.             StringCopy (buffer)) == null)
  1484.             return 1;
  1485.  
  1486.         ++pi->N_Modules;
  1487.  
  1488.         break;
  1489.  
  1490.         case 3:                /* system semaphore    */
  1491.         case 4:                /* shared memory    */
  1492.         break;
  1493.     }
  1494.  
  1495.     ptr = MAKEP(sel, offs);
  1496.     }
  1497.  
  1498. /* Count modules */
  1499.  
  1500.     for (count = 0; count < pi->N_Processes; count++)
  1501.     {
  1502.     for (kount = 0; kount < pi->N_Modules; kount++)
  1503.     {
  1504.         if (pi->V1Processes[count]->modhandle ==
  1505.         pi->V1Modules[kount]->modhandle)
  1506.         {
  1507.         pi->V1Processes[count]->module = kount;
  1508.         break;
  1509.         }
  1510.     }
  1511.     }
  1512.  
  1513. /* Count children */
  1514.  
  1515.     for (count = 0; count < pi->N_Processes; count++)
  1516.     {
  1517.     for (kount = 0; kount < pi->N_Processes; kount++)
  1518.     {
  1519.         if (pi->V1Processes[count]->pid == pi->V1Processes[kount]->ppid)
  1520.         (pi->V1Processes[count]->children)++;
  1521.     }
  1522.     }
  1523.  
  1524.     return FALSE;
  1525. }
  1526.  
  1527. /*
  1528.  * Process the process information
  1529.  */
  1530.  
  1531. static void near PrintV1ProcessTree (pid_t pid, int indent,
  1532.                      struct ProcessInfo *pi)
  1533. {
  1534.     USHORT    count;
  1535.     UCHAR    *mName, pName[256];
  1536.  
  1537.     for (count = 0; count < pi->N_Processes; count++)
  1538.     {
  1539.     if ((pi->V1Processes[count]->ppid == (USHORT)pid) ||
  1540.         ((!indent) && (pi->V1Processes[count]->pid == (USHORT)pid)))
  1541.     {
  1542.         if (pi->V1Processes[count]->module)
  1543.         {
  1544.         mName = pi->V1Modules[pi->V1Processes[count]->module]->modname;
  1545.         DosGetModName (pi->V1Processes[count]->modhandle,
  1546.                    sizeof(pName), pName);
  1547.         }
  1548.  
  1549.         else
  1550.         {
  1551.         mName = "unknown";  /* Zombie process,    */
  1552.         pName[0] = 0;
  1553.         }
  1554.  
  1555.         printf ("%5d %5d %3d %-8s %*s%s\n", pi->V1Processes[count]->pid,
  1556.             pi->V1Processes[count]->ppid,
  1557.             pi->V1Processes[count]->threads, mName, indent, "", pName);
  1558.  
  1559.         PrintV1ProcessTree (pi->V1Processes[count]->pid, indent + 2, pi);
  1560.     }
  1561.     }
  1562. }
  1563.  
  1564.  
  1565. int SortV1Processes (void *p1, void *p2)
  1566. {
  1567.     return (*(V1Process_t **)p1)->pid - (*(V1Process_t **)p2)->pid;
  1568. }
  1569.  
  1570. /*
  1571.  * OS/2 2.x 32-bit version - Display Process Tree
  1572.  */
  1573.  
  1574. static void near V2_DisplayProcessTree (USHORT pid, USHORT indent,
  1575.                     struct V2_ProcessStatus *ps)
  1576. {
  1577.     V2Process_t        *proc;
  1578.     UCHAR        name[256];
  1579.     USHORT        prty;
  1580.  
  1581.     for (proc = PTR (ps->processes, 0);
  1582.      proc -> type != 3;        /* not sure if there isn't    */
  1583.                     /* another termination method    */
  1584.      proc = PTR (proc -> threadlist,
  1585.              proc -> threads * sizeof (V2Thread_t))
  1586.         )
  1587.     {
  1588.     if ((proc->parentid == pid) ||
  1589.         ((!indent) && (proc->processid == pid)))
  1590.     {
  1591.         if (DosGetModName (proc->modulehandle, sizeof (name), name))
  1592.         strcpy(name, "<unknown>");
  1593.  
  1594.         if (DosGetPrty (PRTYS_PROCESS, &prty, proc->processid))
  1595.         prty = 0;
  1596.  
  1597.         printf ("%5d %5d %3d %04x %*s%s\n", proc->processid,
  1598.             proc->parentid, proc->threads, prty, indent, "", name);
  1599.  
  1600.         V2_DisplayProcessTree (proc->processid, indent + 2, ps);
  1601.     }
  1602.     }
  1603. }
  1604.  
  1605. /*
  1606.  * Print the Process Tree
  1607.  */
  1608.  
  1609. int PrintProcessTree (pid_t pid)
  1610. {
  1611.  
  1612. /* Switch on release number */
  1613.  
  1614.     if (_osmajor < 20)
  1615.     {
  1616.     UCHAR            *pBuf = GetAllocatedSpace (0x2000);
  1617.     USHORT            count;
  1618.     struct ProcessInfo    pi;
  1619.  
  1620.     pi.M_Processes = pi.M_Modules = pi.N_Processes = pi.N_Modules = 0;
  1621.     pi.V1Processes = NULL;
  1622.     pi.V1Modules = NULL;
  1623.  
  1624.     if (pBuf == (UCHAR *)NULL)
  1625.         return 1;
  1626.  
  1627.     DosQProcStatus (pBuf, 0x2000);
  1628.  
  1629.     if (Parse_V1ProcessTable (pBuf, &pi))
  1630.        return 1;
  1631.  
  1632.     ReleaseMemoryCell ((void *)pBuf);
  1633.  
  1634.     qsort ((void *)pi.V1Processes, pi.N_Processes, sizeof (V1Process_t *),
  1635.         SortV1Processes);
  1636.  
  1637.         puts ("   PID  PPID TC Name     Program");
  1638.     PrintV1ProcessTree (pid, 0, &pi);
  1639.  
  1640.     for (count = 0; count < pi.N_Processes; count++)
  1641.         ReleaseMemoryCell ((void *)pi.V1Processes[count]);
  1642.  
  1643.     for (count = 0; count < pi.N_Modules; count++)
  1644.     {
  1645.         ReleaseMemoryCell ((void *)pi.V1Modules[count] -> modname);
  1646.         ReleaseMemoryCell ((void *)pi.V1Modules[count]);
  1647.     }
  1648.  
  1649.     ReleaseMemoryCell ((void *)pi.V1Processes);
  1650.     ReleaseMemoryCell ((void *)pi.V1Modules);
  1651.     }
  1652.  
  1653. /*
  1654.  * OS2 2.0 - grap space, get the information and display it
  1655.  */
  1656.  
  1657.     else
  1658.     {
  1659.     struct V2_ProcessStatus    *ps;
  1660.  
  1661.     if ((ps = (struct V2_ProcessStatus *)GetAllocatedSpace (0x8000))
  1662.         == (struct V2_ProcessStatus *)NULL)
  1663.         return 1;
  1664.  
  1665.     DosQProcStatus (ps, 0x8000);
  1666.         puts ("   PID  PPID TC PRI  Program");
  1667.     V2_DisplayProcessTree (pid, 0, ps);
  1668.     ReleaseMemoryCell ((void *)ps);
  1669.     }
  1670.  
  1671.     return 0;
  1672. }
  1673. #endif
  1674.